package com.youtills.core.auth.db.dao;


import com.youtills.core.auth.IAuth;
import com.youtills.core.auth.IAuthenticationDao;
import com.youtills.core.email.EmailMessage;
import com.youtills.core.email.EmailSender;
import com.youtills.core.lang.StringUtil;
import com.youtills.core.random.RandomString;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.text.MessageFormat;
import java.util.Date;
import java.util.HashMap;

/**
 * Created by IntelliJ IDEA.
 * User: ravi
 * Date: 8/14/12
 * Time: 10:43 AM
 * To change this template use File | Settings | File Templates.
 */
public class AuthenticationDao extends BaseAuthDao implements IAuthenticationDao {

    private static final long AUTH_VERIFY_DELAY = 1000L * 60 * 3; //mills * seconds * minutes

    private static final AuthenticationDao instance = new AuthenticationDao();

    private final SqlSessionFactory sqlSessionFactory;
    private final RandomString pwdGenerator;

    private static final char[] PWD_ALLOWED_CHARS = new char[]{
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n',
            'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N',
            'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
            '2', '3', '4', '5', '6', '7', '8', '9',
            '!', '@', '$', '*'
    };

//    private final ConfigItem RESET_PASSWORD_EMAIL_FROM = new ConfigItem("quiggle.reset.password.email.from");
//    private final ConfigItem RESET_PASSWORD_EMAIL_SUBJECT = new ConfigItem("quiggle.reset.password.email.subject");
//    private final ConfigItem RESET_PASSWORD_EMAIL_BODY = new ConfigItem("quiggle.reset.password.email.body");
//    private final ConfigItem QUIGGLE_SERVER_NAME = new ConfigItem("quiggle.server.name");
//    private final ConfigItem QUIGGLE_CONTEXT_NAME = new ConfigItem("quiggle.context.name", "/quiggle");

    private AuthenticationDao() {
        super();
        sqlSessionFactory = getSqlSessionFactory();
        pwdGenerator = new RandomString(10, PWD_ALLOWED_CHARS);
//        ConfigLoader.loadProperties("email-template.properties", false);
    }

    public static AuthenticationDao getInstance() {
        return instance;
    }

    public String hashPassword(String plainPwd){
//        return QuiggleSecurityHelper.hashPassword(plainPwd);
        return  plainPwd;
    }

    public boolean resetPassword(String email){

        SqlSession session = sqlSessionFactory.openSession();
        try {
            String newPassword = pwdGenerator.getNext();
            String hashedPassword = hashPassword(newPassword);
            HashMap<String, Object> params = new HashMap<String, Object>(3);
            params.put("email", email);
            params.put("hashedPassword", hashedPassword);
            params.put("success", false);
            session.update("com.depo.quiggle.auth.db.dao.reset-password", params);

            boolean success = StringUtil.getBoolean(params.get("success"), false);

            if(success){
                EmailMessage message = new EmailMessage(email);
//                message.setFrom(RESET_PASSWORD_EMAIL_FROM.getString());
//                message.setSubject(RESET_PASSWORD_EMAIL_SUBJECT.getString());
                message.setHtml(true);
//                String body = MessageFormat.format(RESET_PASSWORD_EMAIL_BODY.getString(), newPassword, QUIGGLE_SERVER_NAME.getString(), QUIGGLE_CONTEXT_NAME.getString());
//                message.setBody(body);
                EmailSender.send(message);
            }
            session.commit();
            return success;
        }catch (Exception e){
            session.rollback();
            throw new RuntimeException(e);
        } finally {
            session.close();
        }
    }

    public boolean changePassword(int userId, String currentPassword, String newPassword) {
        String hashedNewPassword = hashPassword(newPassword);
        boolean success = changePwd(userId, hashPassword(currentPassword), hashedNewPassword);
        if(!success){
            success = changePwd(userId, currentPassword, hashedNewPassword);
        }
        return success;
    }
    private boolean changePwd(int userId, String hashedCurrentPassword, String hashedNewPassword) {

        SqlSession session = sqlSessionFactory.openSession();
        try {
            HashMap<String, Object> params = new HashMap<String, Object>(3);
            params.put("userId", userId);
            params.put("currentPassword", hashedCurrentPassword);
            params.put("newPassword", hashedNewPassword);
            params.put("success", false);
            session.update("com.depo.quiggle.auth.db.dao.change-password", params);
            session.commit();
            return StringUtil.getBoolean(params.get("success"), false);
        }catch (Exception e){
            session.rollback();
            throw new RuntimeException(e);
        } finally {
            session.close();
        }
    }


    public IAuth authenticateUser(String email, String password){
    	IAuth auth = null;
    	try{
    	auth = authenticate(email, hashPassword(password));
        if(auth == null){
            auth = authenticate(email, password);
        }
        return auth;
    	}catch (Exception e) {
    		e.printStackTrace();
    		return auth;
    	}
    }
    private IAuth authenticate(String email, String hashedPassword){

        SqlSession session = sqlSessionFactory.openSession();
        Auth auth = null;
        try {
            HashMap<String, Object> params = new HashMap<String, Object>(2);
            params.put("userEmail", email);
            params.put("hashedPassword", hashedPassword);
            auth = session.selectOne("com.youtills.core.auth.db.dao.authenticate-user", params);
            if(auth != null){
                auth.getAuthUser().setAuth(auth);
            }
            return auth;
        }catch (Exception e){
            return auth;
        } finally {
            session.close();
        }
    }

    public IAuth getAuth(int authId, String authKey) {

        SqlSession session = sqlSessionFactory.openSession();
        try {
            HashMap<String, Object> params = new HashMap<String, Object>(2);
            params.put("authId", authId);
            params.put("authKey", authKey);
            Auth auth = session.selectOne("com.depo.quiggle.auth.db.dao.authentication-get", params);
            auth.getAuthUser().setAuth(auth);
            return auth;
        }catch (Exception e){
            throw new RuntimeException(e);
        } finally {
            session.close();
        }
    }

    public boolean validateAndExtendAuth(IAuth auth) {
        if(auth != null){
            if(auth instanceof Auth){
                Auth a = (Auth)auth;
                long last = a.getLastValidatedTime();
                long now = System.currentTimeMillis();
                if(last > 1 && (now - last < AUTH_VERIFY_DELAY)){ //once every 3 minutes.
                    return true;
                }
            }
            return validateAndExtend(auth);
        }
        return false;
    }

    private boolean validateAndExtend(IAuth auth){

        SqlSession session = sqlSessionFactory.openSession();
        try {
            HashMap<String, Object> params = new HashMap<String, Object>(4);
            params.put("authId", auth.getAuthId());
            params.put("authKey", auth.getAuthKey());
            params.put("modifiedDate", null);
            params.put("success", false);
            session.update("com.depo.quiggle.auth.db.dao.validate-extend", params);
            session.commit();
            boolean success = StringUtil.getBoolean(params.get("success"), false);
            if(success && auth instanceof Auth){
                Auth a = (Auth)auth;
                a.setLastValidatedTime(System.currentTimeMillis());
                a.setModifiedDate((Date)params.get("modifiedDate"));
            }
            return success;
        }catch (Exception e){
            session.rollback();
            throw new RuntimeException(e);
        } finally {
            session.close();
        }
    }
}
